﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace FlexiPay
{
    public partial class FormulaPage : System.Web.UI.Page
    {
        //(1) when - then validation (2) query generation
        private String pageName = String.Empty;

        #region init

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                pageName = Request.QueryString["PageName"];
                ManageEditable(false);
                BEdit.Visible = false;
                ManageVisibles();
                if (pageName != RuleEngineGenerics.FORMULA)
                    populateFormulaList();
            }
        }

        private void ManageEditable(Boolean editable)
        {
            //buttons
            BApply.Visible = editable;
            BCancel.Visible = editable;
            BEdit.Visible = !editable;
            BCreate.Visible = !editable;

            //list boxes
            LBListColumn.Enabled = editable;
            LBListFormula.Enabled = editable;
            LBListFunction.Enabled = editable;
            LBListSlabs.Enabled = editable;

            //other controls
            TBFormulaName.Enabled = editable;
            DDLSubType.Enabled = editable;
            DDLReturnType.Enabled = editable;
            TBFromDate.Enabled = editable;
            TBToDate.Enabled = editable;

            //query parts
            TBWhenPart.Enabled = editable;
            TBThenPart.Enabled = editable;
            TBGroupBy.Enabled = editable;
        }

        private void ManageVisibles()
        {
            //list boxes
            LabelFieldList.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FieldList");
            LBListColumn.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FieldList");
            LabelFormulaList.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FormulaList");
            LBListFormula.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FormulaList");
            LabelFunctionList.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FunctionList");
            LBListFunction.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FunctionList");
            LabelSlabsList.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "SlabsList");
            LBListSlabs.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "SlabsList");

            //other controls
            DDLSubType.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "SubType");
            LabelSubType.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "SubType");
            DDLReturnType.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ReturnType");
            LabelReturnType.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ReturnType");
            LabelFromDate.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FromDate");
            TBFromDate.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "FromDate");
            LabelToDate.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ToDate");
            TBToDate.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ToDate");

            //query parts
            LabelWhen.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "WhenPart");
            TBWhenPart.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "WhenPart");
            LabelThen.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ThenPart");
            TBThenPart.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ThenPart");
            LabelGroupBy.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "GroupByPart");
            TBGroupBy.Visible = RuleEngineGenerics.checkIfRequiredOnPage(pageName, "GroupByPart");

            //set page header
            LableTitle.Text = RuleEngineGenerics.getTitle(pageName);
            return;
        }
        #endregion

        #region display details
        //populate formula details
        protected void LBLHSFormula_DataBinding(object sender, EventArgs e)
        {
            SDSFormula.SelectCommand = RuleEngineGenerics.getLHSListByType(pageName);
        }

        protected void LBLHSFormula_SelectedIndexChanged(object sender, EventArgs e)
        {
            displayFormula();
            ManageEditable(false);
        }

        private void displayFormula()
        {
            DataRow dr = retrieveDetails();
            if (dr == null) return;
            else displayDetails(dr);

            //formula list is based on SubType, so the formula list box 
            //should be re-retrieved after formula details are updated
            populateFormulaList();

        }

        private DataRow retrieveDetails()
        {
            //if nothing is selected return - do nothing
            if (LBLHSFormula.SelectedIndex < 0) return null;

            //retrieve details in a row
            String query = RuleEngineGenerics.getDetailsByType(Convert.ToInt32(LBLHSFormula.SelectedValue));
            DataTable dt = DataBaseMethods.ExecuteSelectQuery(query);

            //if there are no rows or there are more than one rows throw error, their must be only one row
            if (dt == null || dt.Rows.Count != 1)
            {
                WebMsgBox.Show("There are no entries for selected Formula/Rule.");
                return null;
            }

            return dt.Rows[0];
        }

        private void displayDetails(DataRow entry)
        {
            TBFormulaName.Text = entry["Name"].ToString();
            DDLReturnType.SelectedValue = entry["ReturnType"].ToString();
            DDLSubType.SelectedValue = entry["SubType"].ToString();
            TBFromDate.Text = Convert.ToDateTime(entry["FromDate"].ToString()).ToShortDateString();
            TBToDate.Text = Convert.ToDateTime(entry["ToDate"].ToString()).ToShortDateString();
            TBWhenPart.Text = entry["WhenPart"].ToString();
            TBThenPart.Text = entry["ThenPart"].ToString();
            TBGroupBy.Text = entry["GroupByPart"].ToString();
        }
        #endregion

        #region load boxes data
        //populate dropdowns
        protected void DDLSubType_DataBinding(object sender, EventArgs e)
        {
            SDSSubType.SelectCommand = RuleEngineGenerics.getSubType(pageName);
        }
        protected void DDLReturnType_DataBinding(object sender, EventArgs e)
        {
            SDSReturnType.SelectCommand = RuleEngineGenerics.getReturnTypes();
        }

        //populate formula list
        protected void DDLSubType_SelectedIndexChanged(object sender, EventArgs e)
        {
            populateFormulaList();
        }
        private void populateFormulaList()
        {
            //get the type
            string SubType = String.Empty;
            if (pageName.Equals(RuleEngineGenerics.FORMULA)) SubType = DDLSubType.SelectedValue;
            else SubType = pageName;

            String query = RuleEngineGenerics.getListBySubType(SubType, LBLHSFormula.SelectedValue);
            LBListFormula.DataSource = DataBaseMethods.ExecuteSelectQuery(query);
            LBListFormula.DataBind();
        }

        //populate function list
        protected void LBListFunction_Load(object sender, EventArgs e)
        {
            populateFunctionList();
        }
        private void populateFunctionList()
        {
            string query = RuleEngineGenerics.getFunctionList();
            LBListFunction.DataSource = DataBaseMethods.ExecuteSelectQuery(query);
            LBListFunction.DataBind();
        }

        //populate column list
        protected void LBListField_Load(object sender, EventArgs e)
        {
            populateColumnList();
        }
        private void populateColumnList()
        {
            string query = RuleEngineGenerics.getQueriableColumnList(pageName);
            LBListColumn.DataSource = DataBaseMethods.ExecuteSelectQuery(query);
            LBListColumn.DataBind();
        }

        //populate slabs list
        protected void LBListSlabs_Load(object sender, EventArgs e)
        {
            populateSlabsList();
        }
        private void populateSlabsList()
        {
            string query = RuleEngineGenerics.getSlabsList();
            LBListSlabs.DataSource = DataBaseMethods.ExecuteSelectQuery(query);
            LBListSlabs.DataBind();
        }
        #endregion

        #region buttons at work
        protected void BCancel_Click(object sender, EventArgs e)
        {
            ManageEditable(false);
            displayFormula();
            ViewState["EditMode"] = "None";
        }

        protected void BEdit_Click(object sender, EventArgs e)
        {
            ManageEditable(true);
            ViewState["EditMode"] = "Edit";
        }

        protected void BCreate_Click(object sender, EventArgs e)
        {
            ManageEditable(true);
            resetPage();
            ViewState["EditMode"] = "Create";
        }

        protected void BApply_Click(object sender, EventArgs e)
        {
            //check values entered on page before saving
            if (!checkParameterValues()) return;
            //check date ranges
            if (!RuleEngineGenerics.validateDates(TBFromDate.Text, TBToDate.Text)) return;
            //check if the expressions entered are valid
            if (!isValidExpression()) return;
            //save to database
            if (!saveFormulaDetails()) return;
            //set editables false
            ManageEditable(false);
        }

        private void resetPage()
        {
            TBFormulaName.Text = String.Empty;
            populateFormulaList();
            TBFromDate.Text = RuleEngineGenerics.getDefaultFromDate();
            TBToDate.Text = RuleEngineGenerics.getDefaultToDate();
            TBWhenPart.Text = String.Empty;
            TBThenPart.Text = String.Empty;
            TBGroupBy.Text = String.Empty;
        }
        #endregion

        #region Validation Section
        private bool checkParameterValues()
        {
            //name is a must
            if (String.IsNullOrWhiteSpace(TBFormulaName.Text))
            {
                WebMsgBox.Show("Please enter a valid Name.");
                return false;
            }

            //check When part 
            if (!RuleEngineGenerics.checkIfRequiredOnPage(pageName, "WhenPart"))
            {
                //not required set it to NULL
                TBWhenPart.Text = "NULL";
            }
            else
            { //required
                if (String.IsNullOrWhiteSpace(TBWhenPart.Text))
                {
                    WebMsgBox.Show("Please enter a valid Condition.");
                    return false;
                }
            }

            //check Then part 
            if (!RuleEngineGenerics.checkIfRequiredOnPage(pageName, "ThenPart"))
            {
                //not required set it to NULL
                TBThenPart.Text = "NULL";
            }
            else
            { //required
                if (String.IsNullOrWhiteSpace(TBThenPart.Text))
                {
                    WebMsgBox.Show("Please enter a valid Expression/Computation.");
                    return false;
                }
            }

            //group by is never mandatory, set it to NULL if empty
            if (String.IsNullOrWhiteSpace(TBGroupBy.Text))
                TBGroupBy.Text = "NULL";

            return true;
        }

        private bool isValidExpression()
        {
            WebMsgBox.Show("Validation are not yet implemented");
            return true;
        }
        #endregion

        #region db section
        private Boolean saveFormulaDetails()
        {
            NameValueCollection formulaDetails = new NameValueCollection();
            formulaDetails.Add("Name", TBFormulaName.Text);
            formulaDetails.Add("Type", pageName);
            formulaDetails.Add("SubType", DDLSubType.SelectedValue);
            formulaDetails.Add("FromDate", TBFromDate.Text);
            formulaDetails.Add("ToDate", TBToDate.Text);
            formulaDetails.Add("ReturnType", DDLReturnType.SelectedValue);
            formulaDetails.Add("WhenPart", TBWhenPart.Text);
            formulaDetails.Add("ThenPart", TBThenPart.Text);
            formulaDetails.Add("GroupByPart", TBGroupBy.Text);
            formulaDetails.Add("FinalQuery", RuleEngineGenerics.formulateQuery(TBWhenPart.Text, TBThenPart.Text, TBGroupBy.Text));
            formulaDetails.Add("CreatedBy", GlobalVariables.loginId);
            formulaDetails.Add("CreatedOn", DateTime.Now.ToString());

            return performDBOperation(formulaDetails);
        }

        private Boolean performDBOperation(NameValueCollection inputNMV)
        {
            if (ViewState["EditMode"] == null)
            {
                WebMsgBox.Show("EditMode not specified. " + GlobalVariables.errorMessage);
                return false;
            }

            long rowNo = 0;
            try
            {
                if (ViewState["EditMode"].ToString() == "Create")
                {
                    String insertCommand = DBOperations.generateInsertQuery("Formula", inputNMV);
                    rowNo = DataBaseMethods.ExecuteIdentityInsert(insertCommand, "RowNo");
                }
                else if (ViewState["EditMode"].ToString() == "Edit")
                {
                    rowNo = Convert.ToInt64(LBLHSFormula.SelectedValue);
                    inputNMV.Add("RowNo", LBLHSFormula.SelectedValue);
                    List<String> primary = new List<String> { "RowNo" };
                    String updateCommand = DBOperations.generateUpdateQuery("Formula", inputNMV, primary);
                    DataBaseMethods.ExecuteScalar(updateCommand);
                }
                else
                {
                    WebMsgBox.Show("Invalid EditMode - " + ViewState["EditMode"].ToString() + ". Please report to flexipay.bugs@algosis.com.");
                }
            }
            catch (SqlException ex)
            {
                WebMsgBox.Show("Error occured while trying to update DB. Error: " + ex.Message);
                return false;
            }

            //reload LHS
            LBLHSFormula.DataBind();
            LBLHSFormula.SelectedValue = rowNo.ToString();

            return true;
        }
        #endregion

    }
}